package com.uhuibao.tmall.aspect;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.uhuibao.tmall.annotations.SignatureValidation;
import com.uhuibao.tmall.api.domain.response.ResponseResult;
import com.uhuibao.tmall.common.exception.ServiceException;
import com.uhuibao.tmall.common.utils.ip.IpUtils;
import com.uhuibao.tmall.utils.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.TreeMap;

/**
 * 统一验签：
 * 请求 json 添加 appSecret 字段，按字母大小排序appSecret=huangzj1001&iccid=89852071400081600001&timestamp=1690268820000
 * sha256 加密后，丢到 sign 里，appSecret 不传，sign 必传
 * @author huangzj
 * @date 2023/07/21 18:28
 */
@Slf4j
@Aspect
public class SignAspect {
    // 令牌有效期（默认30分钟）
    @Value("${tmall.tmallSecret}")
    private String tmallSecret;

    @Before("@annotation(signatureValidation)")
    public ResponseEntity<String> doBefore(SignatureValidation signatureValidation) throws Throwable {

        // 请求的地址
        String requestIp = IpUtils.getIpAddr();
        log.info("【用户请求时IP】：{}", requestIp);

        // 接收到请求，记录请求内容
        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();

        TreeMap<String, Object> allParams = HttpUtils.getAllParams(request);

        String queryString = request.getQueryString();
        log.info("【请求参数】：{}", queryString);

        String ts = allParams.get("ts").toString();
        log.info("【ts】：{}", ts);
        log.info("【dq】：{}", System.currentTimeMillis());
        //比较时间，3分钟内为合法请求
        if (System.currentTimeMillis() - Math.abs(Long.parseLong(ts)) > 180000) {

            log.info("【哈哈哈哈】：{}", 111111);
//            throw new ServiceException("TS_EXPIRED", "ts请求已过期");

            ResponseResult responseResult = new ResponseResult();
            responseResult.setTbOrderNo(1L);
            responseResult.setBizType("ttt");
            responseResult.setCoopOrderStatus("FAILD");
            responseResult.setCoopOrderNo("xxx");
            responseResult.setErrCode("TS_EXPIRED");
            responseResult.setErrDesc("ts请求已过期");
            String xmlResponse = convertObjectToXml(responseResult);
            return ResponseEntity.ok().contentType(MediaType.valueOf(MediaType.APPLICATION_XML + ";charset=GBK"))
                    .body(xmlResponse);

        }
//        verifySign(allParams);
        return null;
    }

    protected String convertObjectToXml(Object object) {
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass());
            Marshaller marshaller = jaxbContext.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_ENCODING, "GBK");
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);

            StringWriter stringWriter = new StringWriter();
            stringWriter.write("<?xml version=\"1.0\" encoding=\"GBK\"?>\n");
            marshaller.marshal(object, stringWriter);

            return stringWriter.toString();
        } catch (JAXBException e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 签名验签
     * @param allParams
     */
    private void verifySign(TreeMap<String, Object> allParams) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        // 对方签名
        String sign = allParams.get("sign").toString();
        allParams.remove("sign");
        // 拼接参数字符串
        StringBuilder stringBuilder = new StringBuilder();
        for (Map.Entry<String, Object> entry : allParams.entrySet()) {
            stringBuilder.append(entry.getKey()).append(entry.getValue());
        }
        // 移除最后一个多余的"&"符号
        if (stringBuilder.length() > 0) {
            stringBuilder.setLength(stringBuilder.length() - 1);
        }
        // 打印拼接后的参数字符串
        String concatenatedParams = stringBuilder.toString()+tmallSecret;
        log.info("【拼接后的参数字符串】：{} .", concatenatedParams);
        String mySign = encryptMD5(concatenatedParams);

        log.info("【验签，对方签名】：{}", sign);
        log.info("【验签，我方签名】：{}", mySign);
        // 验签
        Assert.isTrue(StrUtil.equals(sign, mySign), "验签失败");
    }

    // 使用MD5对字符串进行加密
    private static String encryptMD5(String input) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] mdBytes = md.digest(input.getBytes(StandardCharsets.UTF_8));

        StringBuilder sb = new StringBuilder();
        for (byte mdByte : mdBytes) {
            sb.append(Integer.toString((mdByte & 0xff) + 0x100, 16).substring(1));
        }

        return sb.toString();
    }

}

